using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Headsight.BPMN2WF.BPMN.Model
{
    [TestClass]
    public abstract class BPMNBaseElementTestFixture<T, TS> where T : BPMNBaseElement<TS>
    {
        protected T _sut;
        private TS _expectedTElement;
        private String _expectedId;

        [TestInitialize]
        public void SetUpFixture()
        {
            _expectedTElement = CreateTElement();
            _expectedId = "**id**";

            _sut = CreateSut(_expectedTElement, _expectedId);
        }

        protected virtual TS CreateTElement()
        {
            return (TS) Activator.CreateInstance(typeof (TS));
        }

        protected abstract T CreateSut(TS tProcess, string expectedId);

        [TestMethod]
        public void TElement()
        {
            Assert.AreSame(_expectedTElement, _sut.TElement);
        }

        [TestMethod]
        public virtual void Id()
        {
            Assert.AreEqual("block_**id**", _sut.Id);
        }

        [TestMethod]
        public void Equals()
        {
            var actual1 = CreateSut(CreateTElement(), "1");
            var actual2 = CreateSut(CreateTElement(), "1");
            var actual3 = CreateSut(CreateTElement(), "1");
            var actual4 = CreateSut(CreateTElement(), "4");

            Assert.AreEqual(actual1, actual1);
            Assert.AreEqual(actual1, actual2);
            Assert.AreEqual(actual2, actual1);
            Assert.AreEqual(actual2, actual3);
            Assert.AreEqual(actual1, actual3);

            Assert.AreNotEqual(actual1, actual4);
        }

        [TestMethod]
        public void Equals_corner_cases()
        {
            Assert.AreNotEqual(null, CreateSut(CreateTElement(), "1"));
            Assert.AreNotEqual(CreateSut(CreateTElement(), "1"), null);
        }

        [TestMethod]
        public void Equals_inco_Id_null()
        {
            var actual1 = CreateSut(CreateTElement(), null);
            var actual2 = CreateSut(CreateTElement(), null);
            var actual3 = CreateSut(CreateTElement(), "nonNull");

            Assert.AreEqual(actual1, actual2);
            Assert.AreEqual(actual2, actual1);
            Assert.AreNotEqual(actual1, actual3);
            Assert.AreNotEqual(actual3, actual1);
        }

        [TestMethod]
        public void HashCode()
        {
            Assert.AreEqual(CreateSut(CreateTElement(), "1").GetHashCode(), CreateSut(CreateTElement(), "1").GetHashCode());
        }

        [TestMethod]
        public void HashCode_inco_Id_null()
        {
            var actual1 = CreateSut(CreateTElement(), null).GetHashCode();
            var actual2 = CreateSut(CreateTElement(), null).GetHashCode();

            Assert.AreEqual(actual1, actual2);
        }

        [TestMethod]
        public virtual void TestToString()
        {
            var type = _sut.GetType();
            var id = _sut.Id;

            Assert.AreEqual(String.Format("{0}[Id: {1}]", type.Name, id), _sut.ToString());
        }
    }
}
